package com.ts.manage.cms.service;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.ts.framework.domain.cms.CmsPage;
import com.ts.framework.domain.cms.CmsSite;
import com.ts.framework.domain.cms.CmsTemplate;
import com.ts.framework.domain.cms.response.CmsCode;
import com.ts.framework.domain.cms.response.CmsPageResult;
import com.ts.framework.domain.cms.response.CmsPostPageResult;
import com.ts.framework.exception.ExceptionCast;
import com.ts.framework.model.response.CommonCode;
import com.ts.framework.model.response.ResponseResult;
import com.ts.manage.cms.config.RabbitConfig;
import com.ts.manage.cms.dao.CmsPageRepository;
import com.ts.manage.cms.dao.CmsSiteRepository;
import com.ts.manage.cms.dao.CmsTemplateRepository;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Service
@Slf4j
public class CmsPreviewPostService {
    @Autowired
    CmsPageRepository cmsPageRepository;
    @Autowired
    CmsTemplateRepository cmsTemplateRepository;
    @Autowired
    GridFsTemplate gridFsTemplate;
    @Autowired
    GridFSBucket gridFSBucket;
    @Autowired
    RestTemplate restTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    CmsPageService cmsPageService;
    @Autowired
    CmsSiteRepository cmsSiteRepository;

    //页面静态化
    public String getHtmlPage(String pageId) {
        //获取页面模型数据
        Map model = this.getModelByPageId(pageId);
        System.out.println(model);
        if (model == null) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        //获取页面模板内容
        String templateContent = getTemplateByPageId(pageId);
        if (StringUtils.isEmpty(templateContent)) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        //执行静态化
        String html = generateHtml(templateContent, model);
        if (StringUtils.isEmpty(html)) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        return html;
    }

    //生成静态页面
    public String generateHtml(String templateContent, Map model) {
        try {
            //生成配置类
            Configuration configuration = new Configuration(Configuration.getVersion());
            //模板加载器
            StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
            stringTemplateLoader.putTemplate("template", templateContent);
            //配置模板加载器
            configuration.setTemplateLoader(stringTemplateLoader);
            //获取模板
            Template template = configuration.getTemplate("template");
            System.out.println(model);
            String html = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);
            return html;
        } catch (Exception e) {
            log.error("错误信息：" + e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    //获取页面模型数据
    public Map getModelByPageId(String pageId) {
        CmsPage cmsPage = this.findCmsPageById(pageId);
        if (cmsPage == null) {
            //页面为空
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAISNULL);
        }
        String dataUrl = cmsPage.getDataUrl();
        if (StringUtils.isEmpty(dataUrl)) {
            //页面dataUrl为空
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_DATAURLISNULL);
        }
        ResponseEntity<Map> entity = restTemplate.getForEntity(dataUrl, Map.class);
        Map body = entity.getBody();
        System.out.println("Map:" + body);
        return body;
    }

    //获取页面模板内容
    public String getTemplateByPageId(String pageId) {
        CmsPage cmsPage = this.findCmsPageById(pageId);
        if (cmsPage == null) {
            //页面为空
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        String templateId = cmsPage.getTemplateId();
        if (StringUtils.isEmpty(templateId)) {
            //页面模板为空
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_TEMPLATEISNULL);
        }
        Optional<CmsTemplate> optional = cmsTemplateRepository.findById(templateId);
        if (optional.isPresent()) {
            CmsTemplate cmsTemplate = optional.get();
            String fileId = cmsTemplate.getTemplateFileId();
//            fileId = "5fdf177b0f4f733238c3102b";
            //取出模板文件内容
            GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(fileId)));
            //打开下载流对象
            GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
            //创建GridFsResource
            GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
            try {
                String content = IOUtils.toString(gridFsResource.getInputStream(), "utf-8");
                return content;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    //根据pageId查询页面
    public CmsPage findCmsPageById(String id) {
        //参数校验
        if (StringUtils.isEmpty(id)) {
            ExceptionCast.cast(CommonCode.INIT_PARAM);
        }
        Optional<CmsPage> optional = cmsPageRepository.findById(id);
        if (!optional.isPresent()) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        CmsPage cmsPage = optional.get();
        return cmsPage;
    }


    //页面发布
    public ResponseResult postPage(String pageId) {
        //执行静态化
        String htmlPage = this.getHtmlPage(pageId);
        if (StringUtils.isEmpty(htmlPage)) {
            ExceptionCast.cast(CmsCode.CMS_GENERATEHTML_HTMLISNULL);
        }
        //保存静态页面内容
        CmsPage cmsPage = saveHtml(pageId, htmlPage);
        //发送消息
        sentPostPageMsg(pageId);
        return new ResponseResult(CommonCode.SUCCESS);
    }


    //保存静态页面内容
    public CmsPage saveHtml(String pageId, String content) {
        //查询页面
        Optional<CmsPage> optional = cmsPageRepository.findById(pageId);
        if (!optional.isPresent()) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        CmsPage cmsPage = optional.get();
        //存储前先删除原文件
        String htmlFileId = cmsPage.getHtmlFileId();
        if (StringUtils.isNotEmpty(htmlFileId)) {
            gridFsTemplate.delete(Query.query(Criteria.where("_id").is(htmlFileId)));
        }
        //保存html文件到GridFS
        InputStream inputStream = IOUtils.toInputStream(content);
        ObjectId objectId = gridFsTemplate.store(inputStream, cmsPage.getPageName());
        //文件ID
        String fileId = objectId.toString();
        //将文件ID保存到cmspage中
        cmsPage.setHtmlFileId(fileId);
        cmsPageRepository.save(cmsPage);
        return cmsPage;
    }

    //发送页面发布消息
    public void sentPostPageMsg(String pageId) {
        CmsPage cmsPage = this.findCmsPageById(pageId);
        if (cmsPage == null) {
            ExceptionCast.cast(CmsCode.CMS_PAGE_NOTEXISTS);
        }
        Map<String, String> msgMap = new HashMap<>();
        msgMap.put("pageId", pageId);
        //消息内容
        String msg = JSON.toJSONString(msgMap);
        //获取站点ID作为routingKey
        String siteId = cmsPage.getSiteId();
        //发布消息
        rabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE_ROUTING, siteId, msg);
    }

    //添加修改页面信息
    public CmsPageResult saveCmsPage(CmsPage cmsPage) {
        //非空校验
        CmsPage cmsPageDB = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath(
                cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());
        if (cmsPageDB != null) {
            //存在即更新
            return cmsPageService.updateCmsPage(cmsPageDB.getPageId(), cmsPage);
        } else {
            //添加
            return cmsPageService.addCmsPage(cmsPage);
        }
    }

    //一键发布页面
    public CmsPostPageResult postPageQuick(CmsPage cmsPage) {
        //添加页面
        CmsPageResult cmsPageResult = this.saveCmsPage(cmsPage);
        if (!cmsPageResult.isSuccess()) {
            return new CmsPostPageResult(CommonCode.FAIL, null);
        }
        CmsPage cmsPageDB = cmsPageResult.getCmsPage();
        String pageId = cmsPageDB.getPageId();
        //发布页面
        ResponseResult responseResult = this.postPage(pageId);
        if (!responseResult.isSuccess()) {
            return new CmsPostPageResult(CommonCode.FAIL, null);
        }
        //获取页面url=站点域名+站点webpath+页面webpath+页面名称
        //查询站点信息
        String siteId = cmsPageDB.getSiteId();
        CmsSite cmsSite = this.findCmsSiteById(siteId);
        //站点域名
        String siteDomain = cmsSite.getSiteDomain();
        //站点webpath
        String siteWebPath = cmsSite.getSiteWebPath();
        //页面webpath
        String pageWebPath = cmsPageDB.getPageWebPath();
        //页面名称
        String pageName = cmsPageDB.getPageName();
        String pageUrl = siteDomain + siteWebPath + pageWebPath + pageName;
        return new CmsPostPageResult(CommonCode.SUCCESS, pageUrl);
    }


    //根据id查询站点信息
    private CmsSite findCmsSiteById(String id) {
        Optional<CmsSite> optional = cmsSiteRepository.findById(id);
        if (!optional.isPresent()) {
            ExceptionCast.cast(CommonCode.FAIL);
        }
        CmsSite cmsSite = optional.get();
        return cmsSite;
    }
}
